#define DEBUG
using System;
using System.Diagnostics;
using System.Drawing;
using ICSharpCode.TextEditor.Document;

namespace ICSharpCode.TextEditor.UserControls
{
	public class TextEditorSearcher : IDisposable
	{
		private IDocument _document;

		private TextMarker _region;

		public bool MatchCase;

		public bool MatchWholeWordOnly;

		private string _lookFor;

		private string _lookFor2;

		public IDocument Document
		{
			get
			{
				return this._document;
			}
			set
			{
				if (this._document != value)
				{
					this.ClearScanRegion();
					this._document = value;
				}
			}
		}

		public bool HasScanRegion => this._region != null;

		public int BeginOffset
		{
			get
			{
				if (this._region != null)
				{
					return this._region.Offset;
				}
				return 0;
			}
		}

		public int EndOffset
		{
			get
			{
				if (this._region != null)
				{
					return this._region.EndOffset;
				}
				return this._document.TextLength;
			}
		}

		public string LookFor
		{
			get
			{
				return this._lookFor;
			}
			set
			{
				this._lookFor = value;
			}
		}

		public void SetScanRegion(ISelection sel)
		{
			this.SetScanRegion(sel.Offset, sel.Length);
		}

		public void SetScanRegion(int offset, int length)
		{
			Color backgroundColor = this._document.HighlightingStrategy.GetColorFor("Default").BackgroundColor;
			this._region = new TextMarker(offset, length, TextMarkerType.SolidBlock, backgroundColor.HalfMix(Color.FromArgb(160, 160, 160)));
			this._document.MarkerStrategy.AddMarker(this._region);
		}

		public void ClearScanRegion()
		{
			if (this._region != null)
			{
				this._document.MarkerStrategy.RemoveMarker(this._region);
				this._region = null;
			}
		}

		public void Dispose()
		{
			this.ClearScanRegion();
			GC.SuppressFinalize(this);
		}

		~TextEditorSearcher()
		{
			this.Dispose();
		}

		public TextRange FindNext(int beginAtOffset, bool searchBackward, out bool loopedAround)
		{
			Debug.Assert(!string.IsNullOrEmpty(this._lookFor));
			loopedAround = false;
			int beginOffset = this.BeginOffset;
			int endOffset = this.EndOffset;
			int num = beginAtOffset.InRange(beginOffset, endOffset);
			this._lookFor2 = (this.MatchCase ? this._lookFor : this._lookFor.ToUpperInvariant());
			TextRange textRange;
			if (searchBackward)
			{
				textRange = this.FindNextIn(beginOffset, num, searchBackward: true);
				if (textRange == null)
				{
					loopedAround = true;
					textRange = this.FindNextIn(num, endOffset, searchBackward: true);
				}
			}
			else
			{
				textRange = this.FindNextIn(num, endOffset, searchBackward: false);
				if (textRange == null)
				{
					loopedAround = true;
					textRange = this.FindNextIn(beginOffset, num, searchBackward: false);
				}
			}
			return textRange;
		}

		private TextRange FindNextIn(int offset1, int offset2, bool searchBackward)
		{
			Debug.Assert(offset2 >= offset1);
			offset2 -= this._lookFor.Length;
			Func<char, char, bool> func = ((!this.MatchCase) ? ((Func<char, char, bool>)((char lookFor, char c) => lookFor == char.ToUpperInvariant(c))) : ((Func<char, char, bool>)((char lookFor, char c) => lookFor == c)));
			Func<int, bool> func2 = ((!this.MatchWholeWordOnly) ? new Func<int, bool>(IsPartWordMatch) : new Func<int, bool>(IsWholeWordMatch));
			char arg = this._lookFor2[0];
			if (searchBackward)
			{
				for (int num = offset2; num >= offset1; num--)
				{
					if (func(arg, this._document.GetCharAt(num)) && func2(num))
					{
						return new TextRange(num, this._lookFor.Length);
					}
				}
			}
			else
			{
				for (int i = offset1; i <= offset2; i++)
				{
					if (func(arg, this._document.GetCharAt(i)) && func2(i))
					{
						return new TextRange(i, this._lookFor.Length);
					}
				}
			}
			return null;
		}

		private bool IsWholeWordMatch(int offset)
		{
			if (this.IsWordBoundary(offset) && this.IsWordBoundary(offset + this._lookFor.Length))
			{
				return this.IsPartWordMatch(offset);
			}
			return false;
		}

		private bool IsWordBoundary(int offset)
		{
			return offset <= 0 || offset >= this._document.TextLength || !this.IsAlphaNumeric(offset - 1) || !this.IsAlphaNumeric(offset);
		}

		private bool IsAlphaNumeric(int offset)
		{
			char charAt = this._document.GetCharAt(offset);
			return char.IsLetterOrDigit(charAt) || charAt == '_';
		}

		private bool IsPartWordMatch(int offset)
		{
			string text = this._document.GetText(offset, this._lookFor.Length);
			if (!this.MatchCase)
			{
				text = text.ToUpperInvariant();
			}
			return text == this._lookFor2;
		}
	}
}
